package com.xian.minespring.boot;

import com.xian.minespring.io.PropertyResolver;
import com.xian.minespring.utils.ClassPathUtils;
import com.xian.minespring.web.ContextLoaderInitializer;
import com.xian.minespring.web.utils.WebUtils;
import org.apache.catalina.Context;
import org.apache.catalina.LifecycleException;
import org.apache.catalina.Server;
import org.apache.catalina.WebResourceRoot;
import org.apache.catalina.startup.Tomcat;
import org.apache.catalina.webresources.DirResourceSet;
import org.apache.catalina.webresources.StandardRoot;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.lang.management.ManagementFactory;
import java.nio.file.Paths;
import java.util.Set;

public class MineApplication {

    static final String CONFIG_APP_YAML = "/application.yml";
    static final String CONFIG_APP_PROP = "/application.properties";

    final static Logger logger = LoggerFactory.getLogger(MineApplication.class);

    /**
     * 启动服务
     * @param webDir src/main/webapp
     * @param baseDir target/classes
     * @param configClass 配置启动类
     */
    public static void run(String webDir, String baseDir, Class<?> configClass, String... args) throws Exception {
        new MineApplication().start(webDir, baseDir, configClass, args);
    }

    private void start(String webDir, String baseDir, Class<?> configClass, String[] args) throws Exception {
        printBanner();

        final long startTime = System.currentTimeMillis();
        int javaVersion = Runtime.version().feature();
        long pid = ManagementFactory.getRuntimeMXBean().getPid();

        String user = System.getProperty("user.name");
        final String pwd = Paths.get("").toAbsolutePath().toString();

        logger.info("Starting {} using Java {} with PID {} (started by {} in {})", configClass.getSimpleName(), javaVersion, pid, user, pwd);

        var propertyResolver = WebUtils.createPropertyResolver();
        var server = startTomcat(webDir, baseDir, configClass, propertyResolver);

        // started info:
        final long endTime = System.currentTimeMillis();
        final String appTime = String.format("%.3f", (endTime - startTime) / 1000.0);
        final String jvmTime = String.format("%.3f", ManagementFactory.getRuntimeMXBean().getUptime() / 1000.0);
        logger.info("Started {} in {} seconds (process running for {})", configClass.getSimpleName(), appTime, jvmTime);

        server.await();

    }

    private Server startTomcat(String webDir, String baseDir, Class<?> configClass, PropertyResolver propertyResolver) throws Exception {
        int port = propertyResolver.getRequiredProperty("${server.port:8080}", int.class);
        logger.info("starting Tomcat at port {}...", port);
        Tomcat tomcat = new Tomcat();
        tomcat.setPort(port);
        tomcat.getConnector().setThrowOnFailure(true);

        Context context = tomcat.addWebapp("", new File(webDir).getAbsolutePath());
        WebResourceRoot resources = new StandardRoot(context);

        resources.addPreResources(new DirResourceSet(resources, "/WEB-INF/classes", new File(baseDir).getAbsolutePath(), "/"));
        context.setResources(resources);

        context.addServletContainerInitializer(new ContextLoaderInitializer(configClass, propertyResolver), Set.of());
        tomcat.start();
        logger.info("Tomcat started at port {}...", port);
        return tomcat.getServer();
    }


    protected void printBanner() {
        String banner = ClassPathUtils.readString("/banner.txt");
        banner.lines().forEach(System.out::println);
    }

}
